﻿#pragma once

#include "Event/WindowEvent.h"
#include "Event/MouseEvent.h"
#include "Event/KeyboardEvent.h"
#include "Event/TextInputEvent.h"

#include "Object/Object.h"
#include "Widgets/RootWidget.h" 
#include "Containers/ThreadSafePtr.h"
#include "Containers/ScriptDelegateImplement.h"

#include "Window.m.h"

class CWidgetTree;
class RRootWidget;
class RWindowManager;

class CRenderSurface;



RCLASS()
class WHENGINE_API RWindow: public RObject
{
    ROBJECT

public:
    RWindow();
    virtual ~RWindow();

    uint64_t GetWindowID();

    //set window size in screen
    //will auto set Width and Height attribute
    RFUNCTION()
    void SetWindowSize(int64_t InWidth, int64_t InHeight);
    void SetWindowSize(SIntPoint InSize);

    RFUNCTION()
    SIntPoint GetWindowSize();

    //set window position in screen
    //will auto set X and Y attribute
    RFUNCTION()
    void SetWindowPosition(int64_t InX, int64_t InY);
    void SetWindowPosition(SIntPoint InPosition);

    RFUNCTION()
    SIntPoint GetWindowPosition();
public:

    //get window content postion in screen, exclude system border
    RFUNCTION()
    SIntPoint GetWindowContentPosition();

    RFUNCTION()
    SIntPoint ContentSpaceToWindowSpace(const SIntPoint& InContentSpacePosition);

    //get window content size, exclude system border
    RFUNCTION()
    SIntPoint GetWindowContentSize();

    //移动窗口到屏幕中心
    //在调用这个函数之前，必须先设置窗口大小
    //这个函数会修改窗口的X,Y属性
    RFUNCTION()
    void MoveToScreenCenter();

    //get work area of screen, exclude taskbar
    RFUNCTION()
    SRect GetPlacebleArea();

    RFUNCTION()
    void SetWindowTitle(const CString &InTitle);

    RFUNCTION()
    CString GetWindowTitle() { return WindowTitle;};

    RFUNCTION()
    bool IsMaximized() const;

    RFUNCTION()
    void Maximize();

    //check if window is
    //not minimized, maximized, full screen
    RFUNCTION()
    bool IsNormalSizeAndPosition() const;

    RFUNCTION()
    void Restore();

    RFUNCTION()
    bool IsMinimized() const ;

    RFUNCTION()
    void Minimize();

    RFUNCTION()
    bool IsFullScreen() const ;

    RFUNCTION()
    void FullScreen();

    //显示系统边框
    //同时系统也会给窗口添加一个默认的白色背景
    RFUNCTION()
    void ShowSystemBorder();

    //隐藏系统边框
    //窗口的默认背景也会消失，如果不绘制背景，窗口内容会透明
    RFUNCTION()
    void HideSystemBorder();

    //是否显示系统边框
    RFUNCTION()
    bool IsBorderVisible() const;

    //clear all widgets in window
    //include default background of window
    //only root widget will be kept
    RFUNCTION()
    void ClearAllWigets();

    virtual bool ProcessWindowEvent(const SWindowEvent& WindowEvent);

    virtual bool ProcessMouseEvent(const SMouseButtonEvent& MouseEvent);

    virtual bool ProcessTextInput(const STextInputEvent& BoardkeyEvent);

    virtual bool ProcessKeyboardEvent(const SKeyboardEvent& BoardkeyEvent); 


    TDelegate<void> OnWindowClosed;

    //quit application when window closed
    //will bind OnWindowClosed event
    RFUNCTION()
    void ExitApplicationOnWindowClosed();

    //window will be destroyed in next frame
    RFUNCTION()
    void Close();
    
    //window is closed
    //if window is closed, window  object will be destroyed in next frame
    TWidgetAttribute<bool> Closed=false;

    bool IsClosed();

    //get screen area that can be placed window (exclude taskbar)
    SRect GetScreenPlacableArea();

    //get relative mouse position in window
    SIntPoint GetMousePosition();

    //get mouse position in window content area
    SIntPoint GetMousePositionInContent();

    //enable window get mouse move event when mouse is out of window
    //there is only one window can capture mouse at the same time
    void StartCaptureMouse();

    void StopCaptureMouse();

    //set window visible is true
    //and immediately show window
    RFUNCTION()
    void Show();

    //set window visible is false
    //and immediately hide window
    RFUNCTION()
    void Hide();

    //determine if window is visible
    //in next frame
    RFIELD()
    TWidgetAttribute<bool> Visible;
    
    RFUNCTION()
    bool IsVisible() const;

    RFUNCTION()
    void SetOpcity(float InOpacity);

    //will not receive any event if this window is disabled
    void EnableWindow(bool bEnable);
    bool IsWindowEnabled() const;

    //bring this window to front
    RFUNCTION()
    void BringToFront();

    RFUNCTION()
    void HideInTaskbar();

    //if this window is modal window and user click other window,
    // this window will blink
    void NotifyBlinkModalWindow();
    TDelegate<void> OnBlinkModalWindow;

    RFIELD()
    TScriptDelegate<void(
        uint64_t /*获得焦点的窗口ID,可能为0*/
        )> OnLostFocus;
        
    RFIELD()
    TScriptDelegate<void()> OnGotFocus;
    
    bool IsFocused() const;
protected:
    CString WindowTitle;

    //ISytemWindowInterface *SystemWindow=nullptr;

    friend class RWindowManager;

    bool bIsClosed=false;
    bool bIsFocused=false;
public:
    void Tick(float DeltaSeconds);
    void PaintWidgets();

    RFUNCTION()
    TSharedObjectPtr<RRootWidget> GetRootWidget();

    CWidgetTree* GetWidgetTree();

    RWindowManager* GetWindowManager();
protected:
    CWidgetTree* WidgetTree;

    TSharedObjectPtr<RRootWidget> RootWidget;
    
public:
    bool bIsModalWindow=false;

    TDelegate<void> OnResized;

public:
    /// @brief attach a pop window to this window, attched window will be closed when mouse click this window 
    /// by the way, this window will be the parent window of attached window
    /// @param InPopWindow the window will be attached
    /// @param InKeepAliveArea if mouse is in this area, the pop window will not be closed
    void AttachPopWindow(RWindowPtr InPopWindow
        ,TDelegate<SRect> InKeepAliveArea= nullptr
    );

    void CloseAttachedPopWindow();
protected:
    //only allow one pop window attached to this window
    RWindowPtr AttachedPopWindow;
    TDelegate<SRect> KeepPopWindowAliveArea;

public:
    
    /// @brief set a window as parent window, if parent window is closed, this window will be closed too
    /// @param InParentWindow 
    void SetParentWindow(RWindowPtr InParentWindow);
    RWindowPtr GetParentWindow();
protected:
    RWindowWeakPtr ParentWindow;
    TVector<RWindowWeakPtr> SubWindows;

public:
    std::shared_ptr<CRenderSurface> RenderSurface;

};